/**
 * API client for making HTTP requests to the chat server
 */
class ApiClient {
    constructor(baseUrl = '') {
        this.baseUrl = baseUrl;
        this.defaultHeaders = {
            'Content-Type': 'application/json'
        };
    }

    /**
     * Make a generic HTTP request
     */
    async request(endpoint, options = {}) {
        const url = `${this.baseUrl}${endpoint}`;
        const config = {
            method: 'GET',
            headers: { ...this.defaultHeaders },
            ...options
        };

        // Add request body if provided
        if (config.body && typeof config.body === 'object') {
            config.body = JSON.stringify(config.body);
        }

        try {
            const response = await fetch(url, config);
            
            // Parse response
            let data;
            const contentType = response.headers.get('content-type');
            if (contentType && contentType.includes('application/json')) {
                data = await response.json();
            } else {
                data = await response.text();
            }

            // Handle HTTP errors
            if (!response.ok) {
                const error = new Error(data.error || data.message || `HTTP ${response.status}`);
                error.status = response.status;
                error.response = data;
                throw error;
            }

            return data;
        } catch (error) {
            if (error.name === 'TypeError' && error.message.includes('fetch')) {
                // Network error
                throw new Error('Unable to connect to server. Please check your internet connection.');
            }
            throw error;
        }
    }

    /**
     * GET request
     */
    async get(endpoint, params = {}) {
        const url = new URL(endpoint, window.location.origin);
        Object.keys(params).forEach(key => {
            if (params[key] !== undefined && params[key] !== null) {
                url.searchParams.append(key, params[key]);
            }
        });

        return this.request(url.pathname + url.search);
    }

    /**
     * POST request
     */
    async post(endpoint, body = {}) {
        return this.request(endpoint, {
            method: 'POST',
            body
        });
    }

    /**
     * PUT request
     */
    async put(endpoint, body = {}) {
        return this.request(endpoint, {
            method: 'PUT',
            body
        });
    }

    /**
     * DELETE request
     */
    async delete(endpoint) {
        return this.request(endpoint, {
            method: 'DELETE'
        });
    }

    /**
     * Create a new room
     */
    async createRoom(roomData) {
        const { name, password, maxUsers, creatorNickname } = roomData;
        
        if (!isValidRoomName(name)) {
            throw new Error('Invalid room name. Room name must be 1-50 characters long.');
        }

        if (!isValidNickname(creatorNickname)) {
            throw new Error('Invalid nickname. Nickname must be 1-30 characters long and contain only letters, numbers, spaces, and basic punctuation.');
        }

        return this.post('/api/rooms', {
            name: name.trim(),
            password: password || null,
            maxUsers: parseInt(maxUsers) || 50,
            creatorNickname: creatorNickname.trim()
        });
    }

    /**
     * Get room information
     */
    async getRoomInfo(roomId) {
        if (!roomId) {
            throw new Error('Room ID is required');
        }

        return this.get(`/api/rooms/${roomId}`);
    }

    /**
     * Prepare to join a room (validation step)
     */
    async prepareJoinRoom(roomId, userData) {
        const { nickname, password } = userData;
        
        if (!roomId) {
            throw new Error('Room ID is required');
        }

        if (!isValidNickname(nickname)) {
            throw new Error('Invalid nickname. Nickname must be 1-30 characters long and contain only letters, numbers, spaces, and basic punctuation.');
        }

        return this.post(`/api/rooms/${roomId}/join`, {
            nickname: nickname.trim(),
            password: password || null
        });
    }

    /**
     * Validate an invite code
     */
    async validateInvite(inviteCode) {
        if (!inviteCode) {
            throw new Error('Invite code is required');
        }

        return this.get(`/api/invite/${inviteCode}`);
    }

    /**
     * Get server statistics
     */
    async getStats() {
        return this.get('/api/stats');
    }

    /**
     * Health check endpoint
     */
    async healthCheck() {
        try {
            const response = await fetch('/api/stats');
            return response.ok;
        } catch (error) {
            return false;
        }
    }
}

/**
 * Global API client instance
 */
const api = new ApiClient();

/**
 * Room API helpers
 */
const roomApi = {
    /**
     * Create a room with form validation
     */
    async create(formData) {
        try {
            const result = await api.createRoom(formData);
            
            // Store room info in session storage for quick access
            sessionStorage.set('currentRoom', {
                id: result.room.id,
                name: result.room.name,
                inviteCode: result.room.inviteCode,
                inviteUrl: result.inviteUrl,
                createdAt: new Date().toISOString()
            });

            // Store creator user session from server response
            sessionStorage.set('currentUser', {
                nickname: formData.creatorNickname.trim(),
                roomId: result.room.id,
                userId: result.user.id, // Use server-generated user ID
                isCreator: true,
                joinedAt: result.user.joinedAt
            });

            // Also store userId separately for WebSocket connection
            sessionStorage.set('userId', result.user.id);

            return result;
        } catch (error) {
            console.error('Failed to create room:', error);
            throw error;
        }
    },

    /**
     * Join a room with form validation
     */
    async join(roomId, userData) {
        try {
            const result = await api.prepareJoinRoom(roomId, userData);
            
            // Store user info in session storage
            sessionStorage.set('currentUser', {
                nickname: userData.nickname.trim(),
                roomId: roomId,
                joinedAt: new Date().toISOString()
            });

            return result;
        } catch (error) {
            console.error('Failed to join room:', error);
            throw error;
        }
    },

    /**
     * Validate and get invite information
     */
    async validateInvite(inviteCode) {
        try {
            const result = await api.validateInvite(inviteCode);
            
            if (result.valid && result.room) {
                // Store invite info temporarily
                sessionStorage.set('inviteInfo', {
                    code: inviteCode,
                    room: result.room,
                    validatedAt: new Date().toISOString()
                });
            }

            return result;
        } catch (error) {
            console.error('Failed to validate invite:', error);
            throw error;
        }
    },

    /**
     * Get room information with caching
     */
    async getInfo(roomId) {
        try {
            // Check cache first
            const cached = sessionStorage.get(`room_${roomId}`);
            const cacheExpiry = 5 * 60 * 1000; // 5 minutes
            
            if (cached && (new Date() - new Date(cached.cachedAt)) < cacheExpiry) {
                return cached.data;
            }

            // Fetch fresh data
            const result = await api.getRoomInfo(roomId);
            
            // Cache the result
            sessionStorage.set(`room_${roomId}`, {
                data: result,
                cachedAt: new Date().toISOString()
            });

            return result;
        } catch (error) {
            console.error('Failed to get room info:', error);
            throw error;
        }
    }
};

/**
 * Connection monitoring
 */
class ConnectionMonitor {
    constructor() {
        this.isOnline = navigator.onLine;
        this.listeners = [];
        
        this.setupEventListeners();
    }

    setupEventListeners() {
        window.addEventListener('online', () => {
            this.isOnline = true;
            this.notifyListeners('online');
        });

        window.addEventListener('offline', () => {
            this.isOnline = false;
            this.notifyListeners('offline');
        });
    }

    addListener(callback) {
        this.listeners.push(callback);
    }

    removeListener(callback) {
        this.listeners = this.listeners.filter(listener => listener !== callback);
    }

    notifyListeners(status) {
        this.listeners.forEach(callback => {
            try {
                callback(status, this.isOnline);
            } catch (error) {
                console.error('Error in connection listener:', error);
            }
        });
    }

    async checkServerConnection() {
        try {
            const isHealthy = await api.healthCheck();
            return isHealthy;
        } catch (error) {
            return false;
        }
    }
}

// Global connection monitor instance
const connectionMonitor = new ConnectionMonitor();

/**
 * Request timeout wrapper
 */
function withTimeout(promise, timeoutMs = 10000) {
    return Promise.race([
        promise,
        new Promise((_, reject) => {
            setTimeout(() => {
                reject(new Error(`Request timeout after ${timeoutMs}ms`));
            }, timeoutMs);
        })
    ]);
}

/**
 * Retry wrapper for API calls
 */
async function withRetry(apiCall, maxRetries = 3, delay = 1000) {
    let lastError;
    
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
            return await apiCall();
        } catch (error) {
            lastError = error;
            
            // Don't retry for client errors (4xx)
            if (error.status >= 400 && error.status < 500) {
                throw error;
            }
            
            // Don't retry on last attempt
            if (attempt === maxRetries) {
                break;
            }
            
            // Wait before retry
            await new Promise(resolve => setTimeout(resolve, delay * attempt));
        }
    }
    
    throw lastError;
}

/**
 * Generate a unique user ID for client-side session management
*/
function generateUserId() {
    return 'user_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
}

// Export for use in other modules
export {
    api,
    roomApi,
    connectionMonitor,
    withTimeout,
    withRetry,
    generateUserId
}